// type StreamTarget = ReadableStreamDefaultReader<Uint8Array>
// type StreamStatus = 'reading' | 'end' | 'stop' | 'error' | null
// type ReadCbType = { status: StreamStatus; message_id; errorCode? | null }

function detchIsBrChar (content, cur) {
  let index = 0
  while (content[cur + index] === '\n' || content[cur + index] === '\r') {
    index += 1
  }
  return index
}
// 获取当前字符串后续的换行符
function getRestLine (content, cur) {
  let index = detchIsBrChar(content, cur)
  if (!index) return 0
  if (content[cur] === '\n') {
    while (content[cur + index] === '\n') {
      index += 1
    }
    return index
  }
  return 0
}

function getStrongLine (content, cur) {
  const char = content[cur]
  if (char === '*') {
    let index = 1
    while (content[cur + index] === '*') {
      index += 1
    }
    return index
  }
  return 0
}

function getOlLine (content, cur) {
  let index = detchIsBrChar(content, cur)
  const next = content[cur + index]
  if (index > 0 && /\d/.test(next)) {
    index = index + 1
    while (/\d/.test(content[cur + index])) {
      index += 1
    }
    const last = content[cur + index]
    if (last === '.') {
      index += 1
      return index
    }
  }
  return 0
}

// 获取特殊的字符，比如换行符，空格，制表符，回车符，markdown格式的强调符号
function getSpecilyChars (content, cur) {
  const olLen = getOlLine(content, cur)
  if (olLen) return olLen
  const brLen = getRestLine(content, cur)
  if (brLen) return brLen
  const strngLen = getStrongLine(content, cur)
  if (strngLen) return strngLen
  return 0
}
export function createReadCharFunc (key) {
  return function (target, content) {
    return new Promise((resolve) => {
      let index = 0
      function readString () {
        if (index >= content.length) return resolve(null)
        const char = content[index]
        // 逐个读取字符的时候如果是换行符，渲染HTML换行符的时候会导致渲染抖动，直接一次性读取
        const restLine = getRestLine(content, index)
        if (restLine > 0) {
          ;(target[key]) += content.slice(index, index + restLine)
          index += restLine
        } else {
          ;(target[key]) += char
          index++
        }
        window.requestAnimationFrame(() => readString())
      }
      readString()
    })
  }
}

class QueueReponseText {
  queue= []
  status= null
  errorCode= null
  errorInfo = null
  target = null
  readEnd = false
  messageId = ''
  isSyncRead = false // 同步读取模式，用于处理一次性数据
  restBuffer = ''
  readCb = null // 读取结束回调
  tmpContent = ''
  tmpThought = '' // 深度思考内容
  isStartReadChar = false
  isCombineContent = false
  isCombineContentEnd = false

  /**
   * 读取流式内容
   */
  readStream (stream, target) {
    this.reset()
    this.target = target
    // console.log(this.target, '-----target')
    return new Promise((resolve) => {
      this.readCb = (opts) => resolve(opts)
      this.read(stream)
    })
  }
  async read (stream) {
    let done = false
    const decoder = new TextDecoder('utf-8')
    while (!done) {
      const result = await stream.read()
      if (this.status === 'stop') {
        this.readEnd = true
        // console.log('stop end: ', this.queue)
        break
      }
      if (result.done) {
        done = true
        this.readEnd = true
        // console.log('end: ', this.queue)
        break
      }
      const text = decoder.decode(result.value, { stream: true })
      const item = this.parse(this.restBuffer + text)
      if (item) {
        this.push(item)
      }
    }
    return { status: 'ok', msg: '' }
  }

  parse (str) {
    const items = []
    this.restBuffer = ''
    // console.log(str, 111)
    const strs = str.split('\n')
    strs.forEach((line) => {
      try {
        if (line === '') {
          this.restBuffer += line
        } else {
          const data = JSON.parse(this.restBuffer + line)
          this.restBuffer = ''
          items.push(data)
        }
      } catch (e) {
        this.restBuffer += line
      }
    })
    return items
  }
  stringToJson (str) {
    try {
      return JSON.parse(str)
    } catch (e) {
      return null
    }
  }

  push (items) {
    this.queue = this.queue.concat(items)
    this.combineContent()
    this.startReadChar()
  }

  // eslint-disable-next-line sonarjs/cognitive-complexity
  combineContent (items) {
    if (this.isCombineContent) return
    this.isCombineContent = true
    function combine () {
      const item = this.queue.shift()
      // console.log(item, this.status, this.readEnd, '---------')
      if (['error'].includes(this.status)) {
        // this.destroy()
        this.isCombineContentEnd = true
        return
      }
      if (this.status === 'stop' || this.status === 'end') {
        // this.destroy()
        this.isCombineContentEnd = true
        return
      }
      if (!item && this.readEnd) {
        if (!this.status) {
          // 修复http500错误
          this.status = 'error'
          this.errorCode = 500
          this.errorInfo = '服务器连接异常，请检查网络！'
        }
        // this.destroy()
        this.isCombineContentEnd = true
        return
      }
      if (item?.code && item?.code !== 200) {
        this.status = 'error'
        this.errorCode = item?.code
        this.errorInfo = item
        // this.destroy()
        return
      }
      if (!item && !this.readEnd) {
        window.requestAnimationFrame(() => combine.call(this))
        return
      }
      if (item.is_stop || item.is_interrupt) {
        this.status = 'end'
        this.isCombineContentEnd = true
      }
      const str = item.content
      const strThought = item.thought
      this.messageId = item.message_id
      this.target.message_id = item.message_id
      item.content = ''
      item.thought = ''
      if (!this.target.target) {
        this.target.target = item
      }
      if (item.observation) {
        this.target.observation = this.stringToJson(item.observation)
      }
      if (item.tool) this.target.tool = item.tool
      this.tmpThought += strThought || ''
      this.tmpContent += str || ''
      // console.log('-----: ', strThought, str)
      window.requestAnimationFrame(() => combine.call(this))
    }
    combine.call(this)
  }
  startReadChar () {
    if (this.isStartReadChar) return
    const target = this.target.target
    // if (!target) return
    this.isStartReadChar = true
    const isStop = () => {
      return ['stop', 'error'].includes(this.status)
    }
    const end = () => {
      // this.status = 'end'
      this.destroy()
    }
    const getContent = () => {
      return this.tmpContent
    }
    const isReadEnd = () => {
      return this.isCombineContentEnd
    }

    const getThoughtContent = () => {
      return this.tmpThought
    }

    const endThought = () => {
      this.readCharWithKey({ key: 'content', isStop, end, getContent, isReadEnd, target })
    }

    const isThoughtEnd = () => {
      return !!this.tmpContent.length
    }

    this.readCharWithKey({
      key: 'thought',
      isStop,
      end: endThought,
      getContent: getThoughtContent,
      isReadEnd: isThoughtEnd,
      target
    })
  }

  readCharWithKey (opts) {
    const { key, isStop, end, getContent, isReadEnd, target } = opts
    let index = 0
    const read = () => {
      const stoped = isStop()
      if (stoped) {
        end()
        return
      }
      const content = getContent()
      if (index >= content.length && isReadEnd()) {
        end()
        return
      }
      if (index >= content.length) {
        window.requestAnimationFrame(read.bind(this))
        return
      }

      const char = content[index]
      // 逐个读取字符的时候如果是换行符，渲染HTML换行符的时候会导致渲染抖动，直接一次性读取
      const restLine = getSpecilyChars(content, index)
      if (restLine > 0) {
        target && (target[key] += content.slice(index, index + restLine))
        index += restLine
      } else {
        target && (target[key] += char)
        index++
      }
      window.requestAnimationFrame(() => read())
    }
    read()
  }

  stop () {
    this.status = 'stop'
  }

  destroy () {
    try {
      if (this.readCb) { this.readCb({ status: this.status, message_id: this.messageId, errorCode: this.errorCode, errorInfo: this.errorInfo }) }
    } catch (e) {
      console.log(e)
    }
    // this.reset()
  }

  reset () {
    this.status = null
    this.target = null
    this.queue = []
    this.isSyncRead = false
    this.readCb = null
    this.restBuffer = ''
    this.errorInfo = null
    this.tmpContent = ''
    this.tmpThought = ''
    this.isCombineContent = false
    this.isStartReadChar = false
    this.isCombineContentEnd = false
    this.readEnd = false
  }
}
const queueReponseText = new QueueReponseText()
// if (import.meta.env.DEV) {
//   // @ts-ignore
//   window.QUEUE_TEXT = queueReponseText
// }
export default queueReponseText
